#include "mutex.h"
#include "irq.h"
#include "task.h"

void mutex_init(mutex_t *mutex)
{
    mutex->locked_count = 0;
    mutex->owner        = NULL;
    list_init(&mutex->wait_list);
}
void mutex_lock(mutex_t *mutex)
{
    irq_state_t irq_state    = irq_enter_protect();
    task_t     *current_task = task_current_task();
    if (!mutex_is_locked(mutex))
    {
        mutex->locked_count++;
        mutex->owner = current_task;
    }
    else if (mutex->owner == current_task)
    {
        mutex->locked_count++;
    }
    else
    {
        task_set_block(current_task);
        list_insert_last(&mutex->wait_list, &current_task->wait_node);
        task_dispatch();
    }
    irq_exit_protect(irq_state);
}
void mutex_unlock(mutex_t *mutex)
{
    irq_state_t irq_state    = irq_enter_protect();
    task_t     *current_task = task_current_task();
    if (mutex->owner == current_task)
    {
        if (--mutex->locked_count == 0)
        {
            mutex->owner = (task_t *)0;
            if (list_count(&mutex->wait_list))
            {
                list_node_t *node = list_remove_first(&mutex->wait_list);
                task_t      *task = container_of(node, task_t, wait_node);
                task_set_ready(task);
                // give the lock to new task
                mutex->locked_count = 1;
                mutex->owner        = task;
                task_dispatch();
            }
        }
    }
    irq_exit_protect(irq_state);
}

bool mutex_try_lock(mutex_t *mutex)
{
}
bool mutex_is_locked(mutex_t *mutex)
{
    return mutex->locked_count > 0;
}